package vip.xiaonuo.biz.modular.usersync.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.biz.modular.user.mapper.BizUserMapper;
import vip.xiaonuo.biz.modular.usersync.service.UserSyncService;
import vip.xiaonuo.dev.api.DevConfigApi;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class UserSyncServiceImpl extends ServiceImpl<BizUserMapper, BizUser> implements UserSyncService {
    @Resource
    private DevConfigApi devConfigApi;
    @Resource
    private BizUserMapper bizUserMapper;
    private String users_sync_url;
    private String users_sync_grant_type;
    private String users_sync_client_id;
    private String users_sync_client_secret;
    private String users_sync_decrypted_key;

    private AES aesDecrypt;
//    private AES aesEncrypt;

    @PostConstruct
    public void init() {
        users_sync_url = devConfigApi.getValueByKey("USERS_SYNC_URL");
        users_sync_grant_type = devConfigApi.getValueByKey("USERS_SYNC_GRANT_TYPE");
        users_sync_client_id = devConfigApi.getValueByKey("USERS_SYNC_CLIENT_ID");
        users_sync_client_secret = devConfigApi.getValueByKey("USERS_SYNC_CLIENT_SECRET");
        users_sync_decrypted_key = devConfigApi.getValueByKey("USERS_SYNC_DECRYPTED_KEY");
    }

    @Override
    public String getToken() {
        Map<String, Object> param = new HashMap<>();
        param.put("grant_type", users_sync_grant_type);
        param.put("client_id", users_sync_client_id);
        param.put("client_secret", users_sync_client_secret);
        String respStr = HttpUtil.post(String.format("%s/auth/oauth/token", users_sync_url),param, 1000 * 60);
        JSONObject jsonObject = JSON.parseObject(respStr);
        return jsonObject.getString("token_type") + " " + jsonObject.getString("access_token");
    }

    @Override
    public String getUsersData(int current, int size) {
        log.info("同步一卡通卡号请求参数current={},size={}", current, size);
        HttpRequest httpRequest = HttpUtil.createGet(String.format("%s/api/data/service/wfmrfzngyktxx?current=%s&size=%s",
                users_sync_url,current,size));
        Map<String,String> map = MapUtil.newHashMap(1);
        map.put("Authorization", getToken());
        httpRequest.addHeaders(map);
        HttpResponse httpResponse = httpRequest.execute();
        String json = "";
        if(httpResponse.isOk()) json = httpResponse.body();
        return json;
    }

    @Override
    public String decryptData(String decrypted) {
        if(aesDecrypt == null) {
            aesDecrypt = new AES(Mode.ECB, Padding.PKCS5Padding, users_sync_decrypted_key.getBytes());
        }
        return aesDecrypt.decryptStr(decrypted);
    }

//    @Override
//    public String encryptData(String str) {
//        if(aesEncrypt == null) {
//            aesEncrypt = new AES(Mode.ECB, Padding.PKCS5Padding, "#<Hello$World>@!".getBytes());
//        }
//        return aesEncrypt.encryptHex(str);
//    }

    @Override
    public void syncUsersData(int current,int size) {
        String json = getUsersData(current,size);
        log.info("一卡通卡号同步返回={}", json);
        JSONObject parentJson  = JSONObject.parseObject(json);
        // 如果调用失败
        if(parentJson.getIntValue("code") != 0) {
            // 超时
            if(parentJson.getIntValue("code") == 5) {
                log.info("一卡通卡号同步调用超时,20s后重试");
                try {
                    Thread.sleep(1000 * 20);
                    syncUsersData(current, size); //重试
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return;
        }
        JSONObject jsonData = parentJson.getJSONObject("data");
        JSONArray jsonArray = jsonData.getJSONArray("records");
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            //物理卡号
            String physical_card_number = jsonObject.getString("physical_card_number");
            //电子卡号
            String card_number = jsonObject.getString("card_number");
            log.info("解密前：物理卡号={},电子卡号={}",physical_card_number,card_number);

            if(StringUtils.isBlank(physical_card_number) || StringUtils.isBlank(card_number)) continue;

            String decrypt_physical_card_number = decryptData(physical_card_number);
            String decrypt_card_number = decryptData(card_number);
            // 倒置卡号
            String reversed_decrypt_physical_card_number = reversePhysicCardNo(decrypt_physical_card_number);
            log.info("解密后：物理卡号={},倒置物理卡号={},电子卡号={}",
                    decrypt_physical_card_number, reversed_decrypt_physical_card_number,decrypt_card_number);

            bizUserMapper.updatePhysicalCardNumber(
                    reversed_decrypt_physical_card_number,
                    physical_card_number,
                    decrypt_card_number
            );
        }
        int pages = jsonData.getIntValue("pages");
        if(current > pages) return;
        syncUsersData(current + 1, size);
    }

    /**
     * 倒转卡号
     * @param str
     * @return
     */
    private String reversePhysicCardNo(String str){
        String reversedStr = StringUtils.reverse(str);
        char[] charArr = reversedStr.toCharArray();
        for(int i = 1;i < charArr.length;) {
            char temp = charArr[i - 1];
            charArr[i - 1] = charArr[i];
            charArr[i] = temp;
            i += 2;
        }
        return new String(charArr).toUpperCase();
    }
}
